#include "Console.h"


enum profession getProfession(char*);


Console::Console(void)
{
	memset(&options, 0, sizeof(struct opt));
	initPath();
	pos = new Position(path);
	run = true;
	predefData = false;
	options.interval = 5;
	options.distance = 250;
	guild = 0;
	sock = false;
}


Console::~Console(void)
{
	if(guild != 0)
		_free_guild_ptr(guild);
	if(predefData){
		if(options.guild != 0)
			free(options.guild);
		free(options.server);
	}
}


void Console::initPath(){
	TCHAR path[MAX_PATH];
	DWORD size = MAX_PATH;
	memset(path, 0, size);
	GetEnvironmentVariable(TEXT("APPDATA"), path, size);
	wcscat_s(path, size, TEXT(STD_DIR));
	wcstombs(this->path, path, MAX_PATH);
}


int Console::exec(){
	printf("running setup\n");
	if(!predefData){
		pos->setAccountName(options.user);
		pos->setTracking(options.tracking);
		pos->setUpdateDistance(options.distance);
		pos->setUpdateTime(options.interval);
		if(options.channel != 0)
			pos->setChannelId(options.channel);
	}
	if(options.guild != 0){
		printf("querying guild data from the gw2api\n");
		char *request = _guildAPIRequest(0, options.guild);
		jPtr json = _parseJsonStr(request);
		guild = interprete_guild_info(json);
		_free_jptr(json);
		free(request);
		pos->setGuildId(guild->id);
		printf("\tOK\n");
	}
	if(options.server != 0){
		printf("contacting\t%s\n", options.server);
		if(con.openConnection(options.server) != 0){
			printf("\tFAILED\n");
			return 1;
		}
		sock = false;
	}
	else{
		printf("contacting\t%s on %ud\n", options.ip, options.port);
		if(con.openSockConnection(options.ip, options.port) != 0){
			printf("\tFAILED\n");
			return 1;
		}
		sock = true;
	}
	printf("\tOK\ninitializing shared memory\n");
	if(!pos->initializeSharedMemory()){
		printf("\tFAILED\n");
		con.closeConnection();
		return 2;
	}
	printf("\tOK\n");
	char *send, *recv;
	float oldPos[3], *memPos;
	printf("setup complete\n\n\n");
	int size;
	while(run){
		if(pos->clearForUpdate()){
			send = pos->createSnapshot();
			if(send != 0){
				if(sock){
					size = strlen(send);
					con.sockSend(send, size+1);
					memset(send, '\0', size);
					con.sockRecv(send, size);
					printf("received:\t%s\n\n", send);
					free(send);
				}
				else{
					recv = con.sendData(send);
					printf("received:\t%s\n\n", recv);
					free(recv);
					free(send);
				}
			}
		}
		memPos = pos->getPosition();
		if(memcmp(memPos, oldPos, sizeof(float)*3) != 0){
			memcpy(oldPos, memPos, sizeof(float)*3);
			printf("Position: [%g, %g, %g]\n", oldPos[0], oldPos[1], oldPos[2]);
		}
		Sleep(500);
	}
	if(sock)
		con.closeSockConnection();
	else
		con.closeConnection();
	pos->closeSharedMemory();
	return 0;
}


int Console::load(){
	char dir[256];
	sprintf_s(dir, 256, "%s\\%s", path, QUICK_SAVE_FILE);
	std::ifstream in(dir, std::ios::in | std::ios::binary);
	if(in.fail())
		return 1;
	struct userData uData = {0};
	in.read((char*)&uData, sizeof(struct userData));
	in.close();
	pos->setAccountName(uData.account);
	pos->setChannelId(uData.channel);
	pos->setTracking(uData.tracking);
	pos->setUpdateDistance(uData.distance);
	pos->setUpdateTime(uData.time);
	options.server = (char*)malloc(strlen(uData.server)+1);
	strcpy_s(options.server, strlen(uData.server)+1, uData.server);
	if(strcmp(uData.guild, "<GuildName Here>") != 0){
		options.guild = (char*)malloc(strlen(uData.guild)+1);
		strcpy_s(options.guild, strlen(uData.guild)+1, uData.guild);
	}
	predefData = true;
	return 0;
}


int Console::save(struct userData *data){
	char dir[256];
	if(data == 0)
		return 1;
	sprintf_s(dir, 256, "%s\\%s", path, QUICK_SAVE_FILE);
	std::ofstream out(dir, std::ios::out | std::ios::binary);
	out.write((char*)data, sizeof(struct userData));
	out.close();
	return 0;
}


int Console::loadOld(){
	char updateTime[256], distance[256], check[6];
	struct userData uData = {0};
	sprintf_s(uData.server, 256, "%s\\%s", path, "Gw2MapsConnectionInfo.txt");
	FILE *file;
	fopen_s(&file, uData.server, "r");
	memset(uData.server, 0, 256);
	auto read = [&](char *buffer){char c; int pos = 0; memset(buffer, '\0', 256); 
		while((c=fgetc(file))!='\n' && pos < 256){buffer[pos]=c;pos++;}};
	if(file == 0)
		return 1;
	fscanf_s(file, "%s\t\t\t", check, 6);
	if(strcmp("URL:", check) != 0)
		return 1;
	read(uData.server);
	fscanf_s(file, "Accountname:\t", NULL, 0);
	read(uData.account);
	fscanf_s(file, "GuildID:\t\t", NULL, 0);
	read(uData.guild);
	fscanf_s(file, "ChannelID:\t\t", NULL, 0);
	read(uData.channel);
	fscanf_s(file, "UpdateInterval:\t%s\n", updateTime, 256);
	fscanf_s(file, "UpdateDistance:\t%s\n", distance, 256);
	fclose(file);
	uData.time = atoi(updateTime);
	uData.distance = atoi(distance);
	uData.tracking = false;
	uData.offline = false;
	return save(&uData);
}


int Console::reset(){
	FILE *file;
	char dir[256];
	int result = 0x3;
	sprintf_s(dir, 256, "%s\\%s", path, CHARACTER_FILE);
	fopen_s(&file, dir, "r");
	if(file != 0){
		remove(dir);
		fclose(file);
		printf_s("Character File Deleted\n");
		result &= 0x1;
	}
	result &= loadOld() == 0 ? 0x2 : 0x3;
	if(result == 0)
		printf_s("Applied Changes To Connection Settings\n");
	if(result == 0x3)
		printf_s("No Changes Applied, Your Version Is Up-To-Date\n");
	return result;
}


int Console::update(){
	char args[256];
	sprintf_s(args, 256, "%s %u", UPDATER_EXE, VERSION);
	printf_s("starting update..\n");
	WinExec(args, SW_SHOWNORMAL);
	return 0;
}